// 15.2 推导的上下文
// 模板实参推导不仅仅发生在函数模板调用时，它还会在其他几个上下文中发生。C++ 中主要有以下几种推导上下文：
// -------------------------------------------------------------
// 1. 函数模板调用
// 这是最常见的推导上下文，当调用函数模板而没有显式指定模板参数时，编译器会从函数调用参数推导模板参数：
template <typename T>
void f(T param);

f(42); // 从实参 42 推导 T 为 int

// -------------------------------------------------------------
// 2. 类模板实参推导（CTAD，C++17 引入）
// C++17 引入了类模板实参推导，允许从构造函数参数推导类模板参数：
template <typename T>
class Vector
{
public:
    Vector(std::initializer_list<T> init) { /* ... */ }
};

Vector v = {1, 2, 3}; // C++17 中可以推导 T 为 int
                      // 等价于 Vector<int> v = {1, 2, 3};
// 在 C++17 之前，必须显式指定类模板的模板参数。

// -------------------------------------------------------------
// 3. 函数模板的显式特化
// 当为函数模板编写显式特化时，编译器会尝试推导模板参数：
template <typename T>
void f(T param) { /* 主模板 */ }

// 显式特化
template <>
void f<int>(int param) { /* int 特化 */ }

// -------------------------------------------------------------
// 4. 模板函数的地址获取
// 当获取函数模板的地址时，也需要推导模板参数：
template <typename T>
void f(T param);

void (*p)(int) = &f; // 推导 T 为 int

// -------------------------------------------------------------
// 5. 自动返回类型推导（C++14 引入）
// C++14 允许函数模板使用 auto 作为返回类型，编译器会从 return 语句推导实际返回类型：
template <typename T>
auto square(T x)
{
    return x * x; // 返回类型从这里推导
}

auto result = square(4.2); // result 类型为 double

// -------------------------------------------------------------
// 6. 推导指引（Deduction Guides，C++17 引入）
// C++17 引入了推导指引，可以自定义类模板实参推导规则：
template <typename T>
class Container
{
public:
    Container(T t) { /* ... */ }
};

// 推导指引
template <typename Iter>
Container(Iter, Iter) -> Container<typename std::iterator_traits<Iter>::value_type>;

std::vector<int> v = {1, 2, 3};
Container c(v.begin(), v.end()); // 推导 T 为 int

// -------------------------------------------------------------
// 7. 结构化绑定（C++17 引入）
// C++17 的结构化绑定也涉及类型推导：
template <typename T, typename U>
struct Pair
{
    T first;
    U second;
};

Pair<int, double> p{42, 3.14};
auto [x, y] = p; // x 的类型为 int，y 的类型为 double

// -------------------------------------------------------------
// 总结
// 模板实参推导不仅发生在函数调用时，还会在其他多种上下文中发生。
// C++17 引入了类模板实参推导（CTAD）和推导指引，大大简化了模板的使用。
// 不同的推导上下文可能有不同的推导规则和行为。